import 'cnd.dart';
import 'cnd_operator.dart';
import 'cnd_util.dart';

/// 条件构建器
///
/// 提供链式调用的方式构建查询条件
class Cnds {
  final List<String> _cnds = [];
  final List<dynamic> _parameters = [];
  final Map<String, dynamic> _parameterMap = {};
  int _paramCounter = 0;

  /// 添加条件
  Cnds where(
    String col,
    CndOperator op,
    dynamic value, {
    String? tableAlias,
    bool ignoreNull = true,
    bool caseSensitive = true,
  }) {
    if (ignoreNull && _shouldIgnoreValue(value)) {
      return this;
    }

    final fullcol = tableAlias != null ? '$tableAlias.$col' : col;
    final cnd = _buildCnd(fullcol, op, value, caseSensitive);

    if (cnd.isNotEmpty) {
      _cnds.add(cnd);
    }

    return this;
  }

  /// 等于条件
  Cnds eq(String col, dynamic value,
      {String? tableAlias, bool ignoreNull = true}) {
    return where(col, CndOperator.eq, value,
        tableAlias: tableAlias, ignoreNull: ignoreNull);
  }

  /// 不等于条件
  Cnds ne(String col, dynamic value,
      {String? tableAlias, bool ignoreNull = true}) {
    return where(col, CndOperator.ne, value,
        tableAlias: tableAlias, ignoreNull: ignoreNull);
  }

  /// 大于条件
  Cnds gt(String col, dynamic value,
      {String? tableAlias, bool ignoreNull = true}) {
    return where(col, CndOperator.gt, value,
        tableAlias: tableAlias, ignoreNull: ignoreNull);
  }

  /// 大于等于条件
  Cnds ge(String col, dynamic value,
      {String? tableAlias, bool ignoreNull = true}) {
    return where(col, CndOperator.ge, value,
        tableAlias: tableAlias, ignoreNull: ignoreNull);
  }

  /// 小于条件
  Cnds lt(String col, dynamic value,
      {String? tableAlias, bool ignoreNull = true}) {
    return where(col, CndOperator.lt, value,
        tableAlias: tableAlias, ignoreNull: ignoreNull);
  }

  /// 小于等于条件
  Cnds le(String col, dynamic value,
      {String? tableAlias, bool ignoreNull = true}) {
    return where(col, CndOperator.le, value,
        tableAlias: tableAlias, ignoreNull: ignoreNull);
  }

  /// LIKE条件
  Cnds like(
    String col,
    String value, {
    String? tableAlias,
    bool ignoreNull = true,
    bool caseSensitive = true,
  }) {
    return where(col, CndOperator.like, value,
        tableAlias: tableAlias,
        ignoreNull: ignoreNull,
        caseSensitive: caseSensitive);
  }

  /// NOT LIKE条件
  Cnds notLike(
    String col,
    String value, {
    String? tableAlias,
    bool ignoreNull = true,
    bool caseSensitive = true,
  }) {
    return where(col, CndOperator.notLike, value,
        tableAlias: tableAlias,
        ignoreNull: ignoreNull,
        caseSensitive: caseSensitive);
  }

  /// IS NULL条件
  Cnds isNull(String col, {String? tableAlias}) {
    return where(col, CndOperator.isNull, null,
        tableAlias: tableAlias, ignoreNull: false);
  }

  /// IS NOT NULL条件
  Cnds isNotNull(String col, {String? tableAlias}) {
    return where(col, CndOperator.isNotNull, null,
        tableAlias: tableAlias, ignoreNull: false);
  }

  /// IN条件
  Cnds in_(String col, Iterable values,
      {String? tableAlias, bool ignoreNull = true}) {
    return where(col, CndOperator.in_, values,
        tableAlias: tableAlias, ignoreNull: ignoreNull);
  }

  /// NOT IN条件
  Cnds notIn(String col, Iterable values,
      {String? tableAlias, bool ignoreNull = true}) {
    return where(col, CndOperator.notIn, values,
        tableAlias: tableAlias, ignoreNull: ignoreNull);
  }

  /// BETWEEN条件
  Cnds between(String col, dynamic start, dynamic end, {String? tableAlias}) {
    final range = Range(start: start, end: end);
    return where(col, CndOperator.between, range,
        tableAlias: tableAlias, ignoreNull: false);
  }

  /// NOT BETWEEN条件
  Cnds notBetween(String col, dynamic start, dynamic end,
      {String? tableAlias}) {
    final range = Range(start: start, end: end);
    return where(col, CndOperator.notBetween, range,
        tableAlias: tableAlias, ignoreNull: false);
  }

  /// 自定义条件
  Cnds custom(String cnd, [List<dynamic>? params]) {
    _cnds.add(cnd);
    if (params != null) {
      _parameters.addAll(params);
    }
    return this;
  }

  /// 添加OR分组
  Cnds or(List<Cnds> builders) {
    final orCnds = <String>[];

    for (final builder in builders) {
      final result = builder.build();
      if (result.hasCnds) {
        orCnds.add('(${result.whereClause})');
        _parameters.addAll(result.parameters);
        _parameterMap.addAll(result.parameterMap);
      }
    }

    if (orCnds.isNotEmpty) {
      _cnds.add('(${orCnds.join(' OR ')})');
    }

    return this;
  }

  /// 从 Cnd 列表和数据映射添加条件
  Cnds fromCndList(
    List<Cnd> cndList,
    Map<String, dynamic> dataMap, [
    Map<String, String>? field2Col,
  ]) {
    final result = CndUtil.buildCnd(cndList, dataMap, field2Col);
    if (result.hasCnds) {
      _cnds.add(result.whereClause);
      _parameters.addAll(result.parameters);
      _parameterMap.addAll(result.parameterMap);
    }
    return this;
  }

  /// 构建结果
  CndResult build() {
    return CndResult(
      whereClause: _cnds.join(' AND '),
      parameters: List.unmodifiable(_parameters),
      parameterMap: Map.unmodifiable(_parameterMap),
    );
  }

  /// 清空所有条件
  void clear() {
    _cnds.clear();
    _parameters.clear();
    _parameterMap.clear();
    _paramCounter = 0;
  }

  /// 是否有条件
  bool get hasCnds => _cnds.isNotEmpty;

  /// 条件数量
  int get cndCount => _cnds.length;

  /// 生成参数名
  String _generateParamName([String? prefix]) {
    return '${prefix ?? 'param'}${_paramCounter++}';
  }

  /// 判断是否应该忽略值
  bool _shouldIgnoreValue(dynamic value) {
    if (value == null) return true;
    if (value is String && value.isEmpty) return true;
    if (value is Iterable && value.isEmpty) return true;
    return false;
  }

  /// 构建条件
  String _buildCnd(
      String col, CndOperator op, dynamic value, bool caseSensitive) {
    switch (op) {
      case CndOperator.isNull:
        return '$col IS NULL';

      case CndOperator.isNotNull:
        return '$col IS NOT NULL';

      case CndOperator.in_:
      case CndOperator.notIn:
        return _buildInCnd(col, op, value);

      case CndOperator.between:
      case CndOperator.notBetween:
        return _buildBetweenCnd(col, op, value);

      case CndOperator.like:
      case CndOperator.notLike:
        return _buildLikeCnd(col, op, value, caseSensitive);

      default:
        final paramName = _generateParamName();
        _parameters.add(value);
        _parameterMap[paramName] = value;
        return '$col ${op.sql} ?'; // 使用位置参数而不是命名参数
    }
  }

  String _buildInCnd(String col, CndOperator op, dynamic value) {
    if (value is! Iterable) {
      throw ArgumentError('IN operator requires an Iterable value');
    }

    final valueList = value.toList();
    if (valueList.isEmpty) {
      return op == CndOperator.in_ ? '1=0' : '1=1';
    }

    final placeholders = <String>[];
    for (final item in valueList) {
      final paramName = _generateParamName();
      placeholders.add('?'); // 使用位置参数
      _parameters.add(item);
      _parameterMap[paramName] = item;
    }

    return '$col ${op.sql} (${placeholders.join(', ')})';
  }

  String _buildBetweenCnd(String col, CndOperator op, dynamic value) {
    if (value is! Range) {
      throw ArgumentError('BETWEEN operator requires a Range value');
    }

    final range = value;
    if (!range.isBetween) {
      throw ArgumentError(
          'BETWEEN operator requires both start and end values');
    }

    final startParamName = _generateParamName('start');
    final endParamName = _generateParamName('end');

    _parameters.add(range.start);
    _parameters.add(range.end);
    _parameterMap[startParamName] = range.start;
    _parameterMap[endParamName] = range.end;

    return '$col ${op.sql} ? AND ?'; // 使用位置参数
  }

  String _buildLikeCnd(
      String col, CndOperator op, dynamic value, bool caseSensitive) {
    final paramName = _generateParamName();
    _parameters.add(value);
    _parameterMap[paramName] = value;

    if (caseSensitive) {
      return '$col ${op.sql} ?'; // 使用位置参数
    } else {
      return 'LOWER($col) ${op.sql} LOWER(?)';
    }
  }
}
